import jwt
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, Callable, Union
from fastapi import HTTPException, status, Request, Depends
from functools import wraps
import time
import copy

class JWTTool:
    """JWT工具类 - 集成了装饰器、深浅拷贝等特性"""

    def __init__(self, secret_key: str = "your-secret-key-here", algorithm: str = "HS256"):
        self.secret_key = secret_key
        self.algorithm = algorithm
        self.token_expire_hours = 3  # token有效期3小时
        self.refresh_token_expire_days = 1  # refresh token有效期1天
        self._token_cache = {}  # 简单的token缓存

    @staticmethod
    def create_user_data(username: str, user_id: int, role: str = "user", department: str = "default") -> Dict[str, Any]:
        """静态方法：创建用户数据字典"""
        return {
            "username": username,
            "user_id": user_id,
            "role": role,
            "department": department,
            "created_at": datetime.utcnow().isoformat()
        }

    def create_access_token(self, data: Dict[str, Any]) -> str:
        """创建访问token"""
        to_encode = copy.deepcopy(data)  # 深拷贝避免修改原数据
        expire = datetime.utcnow() + timedelta(hours=self.token_expire_hours)
        to_encode.update({"exp": expire, "type": "access"})
        encoded_jwt = jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
        return encoded_jwt

    def create_refresh_token(self, data: Dict[str, Any]) -> str:
        """创建刷新token"""
        to_encode = copy.deepcopy(data)  # 深拷贝避免修改原数据
        expire = datetime.utcnow() + timedelta(days=self.refresh_token_expire_days)
        to_encode.update({"exp": expire, "type": "refresh"})
        encoded_jwt = jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
        return encoded_jwt

    def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
        """验证token"""
        try:
            payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
            return payload
        except jwt.ExpiredSignatureError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Token已过期"
            )
        except jwt.JWTError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Token无效"
            )

    def refresh_access_token(self, refresh_token: str) -> str:
        """使用refresh token刷新access token"""
        try:
            payload = jwt.decode(refresh_token, self.secret_key, algorithms=[self.algorithm])

            # 检查是否为refresh token
            if payload.get("type") != "refresh":
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="无效的refresh token"
                )

            # 创建新的access token
            user_data = {
                "user_id": payload.get("user_id"),
                "username": payload.get("username"),
                "role": payload.get("role"),
                "department": payload.get("department")
            }

            return self.create_access_token(user_data)

        except jwt.ExpiredSignatureError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Refresh token已过期，请重新登录"
            )
        except jwt.JWTError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Refresh token无效"
            )

    # 装饰器：性能监控
    def performance_monitor(self, func: Callable) -> Callable:
        """装饰器：监控函数执行时间"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            print(f"[性能监控] 函数 {func.__name__} 执行时间: {end_time - start_time:.4f} 秒")
            return result
        return wrapper

    # 装饰器：需要认证
    def require_auth(self, func: Callable) -> Callable:
        """装饰器：验证JWT token"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 从kwargs中获取token
            token = kwargs.get('token')
            if not token:
                raise HTTPException(status_code=401, detail="缺少访问令牌")

            try:
                payload = self.verify_token(token)
                kwargs['user_payload'] = payload  # 将用户信息添加到kwargs
                print(f"[认证] 用户 {payload.get('username')} 访问了 {func.__name__}")
                return func(*args, **kwargs)
            except Exception as e:
                print(f"[认证失败] {str(e)}")
                raise HTTPException(status_code=401, detail=f"Token验证失败: {str(e)}")
        return wrapper

    # 装饰器：缓存结果
    def cache_result(self, expire_seconds: int = 300):
        """装饰器：缓存函数结果"""
        def decorator(func: Callable):
            @wraps(func)
            def wrapper(*args, **kwargs):
                # 创建缓存键
                cache_key = f"{func.__name__}:{str(args)}:{str(kwargs)}"

                # 检查缓存
                if cache_key in self._token_cache:
                    cache_time, cached_result = self._token_cache[cache_key]
                    if time.time() - cache_time < expire_seconds:
                        print(f"[缓存] 使用缓存结果: {cache_key}")
                        return cached_result

                # 执行函数并缓存结果
                result = func(*args, **kwargs)
                self._token_cache[cache_key] = (time.time(), result)
                print(f"[缓存] 缓存新结果: {cache_key}")
                return result
            return wrapper
        return decorator

    # 装饰器：日志记录
    def log_activity(self, activity_type: str = "general"):
        """装饰器：记录用户活动"""
        def decorator(func: Callable):
            @wraps(func)
            def wrapper(*args, **kwargs):
                user_payload = kwargs.get('user_payload', {})
                username = user_payload.get('username', 'anonymous')
                user_id = user_payload.get('user_id', 'unknown')

                print(f"[活动日志] {username}({user_id}) 执行了 {activity_type}: {func.__name__}")

                result = func(*args, **kwargs)

                print(f"[活动日志] {func.__name__} 执行完成")
                return result
            return wrapper
        return decorator

    def clone_user_data(self, user_data: Dict[str, Any], deep: bool = False) -> Dict[str, Any]:
        """深浅拷贝用户数据"""
        if deep:
            return copy.deepcopy(user_data)
        else:
            return copy.copy(user_data)

    def get_token_info(self, token: str) -> Dict[str, Any]:
        """获取token信息"""
        payload = self.verify_token(token)
        return {
            "user_id": payload.get("user_id"),
            "username": payload.get("username"),
            "role": payload.get("role"),
            "department": payload.get("department"),
            "type": payload.get("type"),
            "exp": payload.get("exp"),
            "expires_in": payload.get("exp") - int(datetime.utcnow().timestamp()) if payload.get("exp") else None
        }

    def cleanup_expired_cache(self):
        """清理过期的缓存"""
        current_time = time.time()
        expired_keys = []

        for key, (cache_time, _) in self._token_cache.items():
            if current_time - cache_time > 3600:  # 1小时过期
                expired_keys.append(key)

        for key in expired_keys:
            del self._token_cache[key]

        print(f"[缓存清理] 清理了 {len(expired_keys)} 个过期缓存项")


# FastAPI依赖注入函数
def get_current_user(token: str = Depends(lambda x: x.headers.get("authorization", "").replace("Bearer ", ""))) -> Dict[str, Any]:
    """FastAPI依赖：获取当前用户"""
    if not token:
        raise HTTPException(status_code=401, detail="未提供访问令牌")

    jwt_tool = JWTTool()
    try:
        payload = jwt_tool.verify_token(token)
        return payload
    except Exception as e:
        raise HTTPException(status_code=401, detail=f"Token验证失败: {str(e)}")


# 创建全局JWT工具实例
jwt_tool = JWTTool()
